/*
 * RtspCaster.cpp
 *
 *  Created on: 2016年4月6日
 *      Author: terry
 */

#include "BasicType.h"
#include "RtspCaster.h"
#include "Application.h"
#include "CCasterChannel.h"
#include "MediaType.h"
#include "CLog.h"
#include "RtpPort.h"


av::CasterChannelTable& getChannelTable()
{
	return Application::instance().getChannelTable();
}

void copy(av::MediaFormat& mfmt, const MFormat* fmt)
{
    mfmt.m_codec = fmt->codec;
    mfmt.m_width= fmt->width;
    mfmt.m_height = fmt->height;
    mfmt.m_framerate = fmt->framerate;
    mfmt.m_profile = fmt->profile;
    mfmt.m_clockRate = fmt->clockRate;
	mfmt.m_bitrate = fmt->bitrate;

    mfmt.m_audioCodec = fmt->audioCodec;
    mfmt.m_channels = fmt->channels;
    mfmt.m_sampleRate = fmt->sampleRate;
    mfmt.m_audioProfile = fmt->audioProfile;
    mfmt.m_audioRate = fmt->audioRate;
	mfmt.m_audioBitrate = fmt->audioBitrate;

    if (fmt->vProp && fmt->vPropSize > 0)
    {
        mfmt.m_videoProp.assign((char*)fmt->vProp, fmt->vPropSize);
    }
}

void copyTo(const av::MediaFormat& mfmt, MFormat* fmt)
{
    fmt->codec = mfmt.m_codec;
    fmt->width = mfmt.m_width;
    fmt->height = mfmt.m_height;
    fmt->framerate = mfmt.m_framerate;
    fmt->profile = mfmt.m_profile;
    fmt->clockRate = mfmt.m_clockRate;
	fmt->bitrate = mfmt.m_bitrate;

    fmt->audioCodec = mfmt.m_audioCodec;
    fmt->channels = mfmt.m_channels;
    fmt->sampleRate = mfmt.m_sampleRate;
    fmt->audioProfile = mfmt.m_audioProfile;
    fmt->audioRate = mfmt.m_audioRate;
	fmt->audioBitrate = mfmt.m_audioBitrate;

    fmt->vProp = (uint8_t*)mfmt.m_videoProp.c_str();
    fmt->vPropSize = mfmt.m_videoProp.size();

}




DLLEXPORT int caster_init(int port, const char* ip)
{
	if (port <= 0)
	{
		port = 554;
	}

    CLog::setLogger(CLog::COUT);
    //CLog::setLogger(CLog::SYSLOG);
    CLog::info("caster_init(%d)\n", port);

	int rc = Application::instance().init();
	if (rc != 0)
	{
		return rc;
	}

	rc = Application::instance().getRtspServer().start(ip, port);

	return rc;
}

DLLEXPORT int caster_quit()
{
	Application::instance().quit();

	return 0;
}

DLLEXPORT int caster_set_port_range(int minPort, int maxPort)
{
    if ((minPort < 0) || (maxPort < 0))
    {
        return EINVAL;
    }

    av::RtpPort::setRange(minPort, maxPort);

	return 0;
}

DLLEXPORT int caster_chl_open(HANDLE* handle, const char* name, const MFormat* fmt)
{
	if (!name || strlen(name) <= 0)
	{
		return EINVAL;
	}

	if (!fmt)
	{
		return EINVAL;
	}

	av::CasterChannelTable& chlTable = getChannelTable();
	if (chlTable.exists(name))
	{
		return EEXIST;
	}

    av::MediaFormat format;
    copy(format, fmt);

	av::CasterChannelPtr chl(new av::CCasterChannel());
	int rc = chl->open(name, format);
	if (rc != 0)
	{
		return rc;
	}

	chlTable.put(chl.get(), chl);

    *handle = chl.get();

	return 0;
}

DLLEXPORT void caster_chl_close(HANDLE handle)
{
	av::CasterChannelTable& chlTable = getChannelTable();
    av::CasterChannelPtr chl = chlTable.get(handle);
    if (!chl)
    {
        return;
    }

    std::string name = chl->getName();
	chlTable.remove(handle);

    Application::instance().getRtspServer().closeSession(name);

	return ;
}

DLLEXPORT int caster_chl_is_open(HANDLE handle)
{
	av::CasterChannelTable& chlTable = getChannelTable();
	return chlTable.exist(handle);
}

DLLEXPORT int caster_chl_set_video_prop(HANDLE handle, const uint8_t* prop, int size)
{
    if (!prop || size <= 0)
    {
        return EINVAL;
    }

    av::CasterChannelTable& chlTable = getChannelTable();
    av::CasterChannelPtr chl = chlTable.get(handle);
    if (!chl)
    {
        return ENOENT;
    }

    chl->setVideoProp(prop, size);

    return 0;
}

DLLEXPORT int caster_chl_get_format(HANDLE handle, MFormat* fmt)
{
    if (!fmt)
    {
        return EINVAL;
    }

	av::CasterChannelTable& chlTable = getChannelTable();
	av::CasterChannelPtr chl = chlTable.get(handle);
	if (!chl)
	{
		return ENOENT;
	}

    av::MediaFormat format;
	chl->getMediaFormat(format);
    copyTo(format, fmt);

	return 0;
}

DLLEXPORT int caster_chl_write_video(HANDLE handle, const MPacket* pkt)
{
    //CLog::info("caster_chl_write_video(%p) pkt(%d,%lld)\n", handle, pkt->duration, pkt->pts);

	av::CasterChannelTable& chlTable = getChannelTable();
	av::CasterChannelPtr chl;
    if (!chlTable.find(handle, chl))
    {
        return ENOENT;
    }

    av::MediaPacketPtr mpkt(new av::MediaPacket());
	mpkt->type = av::MEDIA_TYPE_VIDEO;
	mpkt->set(pkt->data, pkt->size);
	mpkt->duration = pkt->duration;
	mpkt->pts = pkt->pts;
	mpkt->flags = pkt->flags;

	chl->write(mpkt);

	return 0;
}

DLLEXPORT int caster_chl_write_audio(HANDLE handle, const MPacket* pkt)
{
	av::CasterChannelTable& chlTable = getChannelTable();
    av::CasterChannelPtr chl;
    if (!chlTable.find(handle, chl))
    {
        return ENOENT;
    }

    av::MediaPacketPtr mpkt(new av::MediaPacket());
    mpkt->type = av::MEDIA_TYPE_AUDIO;
    mpkt->set(pkt->data, pkt->size);
    mpkt->duration = pkt->duration;
    mpkt->pts = pkt->pts;
    mpkt->flags = pkt->flags;

	chl->write(mpkt);

	return 0;
}

DLLEXPORT int caster_chl_set_format(HANDLE handle, MFormat* fmt)
{
    av::CasterChannelTable& chlTable = getChannelTable();
    av::CasterChannelPtr chl;
    if (!chlTable.find(handle, chl))
    {
        return ENOENT;
    }

    av::MediaFormat format;
    copy(format, fmt);

    if (!format.isValid())
    {
        return EINVAL;
    }

    chl->setFormat(format);

    return 0;
}

DLLEXPORT void caster_set_event_callback(RtspCasterEventCallback cb, void* context)
{
    Application::instance().getRtspServer().setCallback(cb, context);
}

DLLEXPORT void caster_enable_log(const char* filename)
{
	CLog::setLogger(CLog::FILE);
    CLog::setFileParam(filename, 10, 2);
}
